#pragma once

#include <mutex>

template <typename T>
class BaseSingleton
{
protected:
    BaseSingleton()          = default;
    virtual ~BaseSingleton() = default;

public:
    BaseSingleton(const BaseSingleton &)            = delete;
    BaseSingleton(BaseSingleton &&)                 = delete;
    BaseSingleton &operator=(const BaseSingleton &) = delete;

public:
    static T *getInstance()
    {
        if (m_instance == nullptr) {
            std::lock_guard<std::mutex> guard(m_mutex);
            if (m_instance == nullptr) {
                m_instance = new T();
            }
        }
        return m_instance;
    }

protected:
    static std::mutex m_mutex;
    static T         *m_instance;
};

template <typename T>
std::mutex BaseSingleton<T>::m_mutex;

template <typename T>
T *BaseSingleton<T>::m_instance = nullptr;